#pragma once

#include "NativeClass.h"
#include "Object/NewObject.h"

#include "TypeInstance.h"
#include "Property.h"
#include "PropertyList.h"

class RObject;

template<typename RObjectType>
requires std::is_base_of_v<RObject,RObjectType>
class  TClass :public CNativeClass
{
public:
	TClass(CString InFullName ,CClass* InBaseClass,std::function<void()> InPostConstructFunction)
	:CNativeClass(
		InBaseClass
		,STypeID(InFullName,true)
		,InPostConstructFunction)
	{
		Instancable=new CTClassInstance(this);
	}

protected:
	class CTClassInstance : public ITypeInstance
	{
	protected:
		CNativeClass* Type;
	public:
		CTClassInstance(CNativeClass* InType)
		{
			Type=InType;
		}

		virtual uint32_t GetSize() override
		{
			return sizeof(RObjectType);
		}

		uint64_t GetInstanceHash(const void *InInstance) const override
		{
			return (uint64_t)InInstance;
		}

		bool IsInstanceEqual(const void *A, const void *B) const override
		{
			return A==B;
		}

		void InitInstance(void * InMemory) 
		{
			new (InMemory) RObjectType();
		}

		void EraseInstance(void* InInstance) override
		{
			//invoke destructor
			reinterpret_cast<RObjectType*>(InInstance)->~RObjectType();
		}

		void CloneInstance(const void* InInstance, void* InMemory) override
		{
			assert(false && "unimplemented");
		}

		void * CreateInstance() override
		{
			assert(false && "script alway allocate share ptr ,rather than raw object pointer");
			return nullptr;
		}

		void ResetAllocated(void * InInstance) override
		{
			assert(false && "script alway allocate share ptr ,rather than raw object pointer");
		}

		virtual bool IsForceConvertableTo(CType * Other) override
		{
			if(!Other->IsClassType())
			{
				return false;
			}

			return Type->IsA(reinterpret_cast<CClass *>(Other));
		}

		CString ToDebugString(const void * Instance) const override
		{
			return Type->GetFullName()+ U"//"+CString::CreateHex((int64_t)Instance,true);
		}
		virtual int64_t GetDebugNamedChildNum(const void * Instance) const override
		{ 
			return Type->Properties->GetNonStaticFieldProperties().Num();
		}

		virtual CString GetDebugNamedChildName(int64_t Index,const void * Instance) const override
		{ 
			return Type->Properties->GetNonStaticFieldProperties()[Index]->GetName();
		}

		virtual CType* GetDebugNamedChildType(int64_t Index,const void * Instance) const override
		{ 
			return Type->Properties->GetNonStaticFieldProperties()[Index]->GetType().BasicType;
		}
		
		virtual const void* GetDebugNamedChildValue(int64_t Index,const void * Instance) const override
		{ 
			return Type->Properties->GetNonStaticFieldProperties()[Index]->FieldProperty->GetValuePointer(Instance);
		}

	};

}; 

